using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
//using System.Drawing;
using System.Text;
using System.Windows.Forms;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace PartBuilder
{
	public partial class MainForm : Form
	{
		NumberDialog number = new NumberDialog();

		EditablePart part = new EditablePart();

		public Point SelectedIndex
		{
			get { return ppPreview.SelectedIndex; }
			set
			{
				ppPreview.SelectedIndex = value;
				ppPreview.Invalidate();
			}
		}

		public MainForm()
		{
			InitializeComponent();

			ppPreview.SelectedPart = part;

			part.Shapes.Add(new EditablePart.Shape());

			System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(16, 16);
			for (int ii = 0; ii < 16; ++ii)
				for (int jj = 0; jj < 16; ++jj)
					bmp.SetPixel(ii, jj, System.Drawing.Color.Black);

			miSColor.Image = bmp;
			miEColor.Image = (System.Drawing.Image)bmp.Clone();

			cbEditMode.SelectedIndex = 0;

			number.Text = "Edge Count";
		}

		protected override void OnResize(EventArgs e)
		{
			ppPreview.Invalidate();
			base.OnResize(e);
		}

		protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
		{
			switch (keyData)
			{
				case Keys.Tab:
					cbEditMode.SelectedIndex = (cbEditMode.SelectedIndex + 1) % cbEditMode.Items.Count;
					break;
				case Keys.F1:
					cbEditMode.SelectedIndex = 0;
					break;
				case Keys.F2:
					cbEditMode.SelectedIndex = 1;
					break;
				case Keys.F3:
					cbEditMode.SelectedIndex = 2;
					break;

				default:
					return base.ProcessCmdKey(ref msg, keyData);
			};

			return true;
		}

		protected override void OnKeyDown(KeyEventArgs e)
		{
			switch (e.KeyData)
			{//A,R,S,C,R
				case Keys.A:
					miAdd_Click(null, EventArgs.Empty);
					break;
				case Keys.R:
					miRemove_Click(null, EventArgs.Empty);
					break;
				case Keys.E:
					miEdgeMenu_Click(null, EventArgs.Empty);
					break;
				case Keys.C:
					miSColor_Click(null, EventArgs.Empty);
					break;
				case Keys.H:
					miHide_Click(null, EventArgs.Empty);
					break;
				case Keys.O:
					miEColor_Click(null, EventArgs.Empty);
					break;
				case Keys.PageUp:
					miShapeUp_Click(null, EventArgs.Empty);
					break;
				case Keys.PageDown:
					miShapeDown_Click(null, EventArgs.Empty);
					break;
				case Keys.Add:
					miEdgeUp_Click(null, EventArgs.Empty);
					break;
				case Keys.Subtract:
					miEdgeDown_Click(null, EventArgs.Empty);
					break;

				default:
					base.OnKeyDown(e);
					break;//I hate C#'s switches
			}
		}

		private void ppPreview_Click(object sender, MouseEventArgs e)
		{
			MouseEventArgs eve = (MouseEventArgs)e;
			Vector2 mouse = new Vector2(eve.X, eve.Y);
			float min = float.MaxValue;
			Point idx = Point.Zero;
			mouse -= new Vector2(ppPreview.ClientSize.Width / 2, ppPreview.ClientSize.Height / 2);

			for (int ii = 0; ii < part.Shapes.Count; ++ii)
			{
				for (int jj = 0; jj < part.Shapes[ii].Edges.Count; ++jj)
				{
					if (part.Shapes[ii].HiddenEdges[jj])
						continue;

					float tmp = Distance2Edge(mouse, part.Shapes[ii].Edges[jj]);

					if (tmp <= min)
					{
						min = tmp;
						idx.X = ii;
						idx.Y = jj;
					}
				}
			}

			if (min < 5)
			{
				SelectedIndex = idx;
			}


			if (e.Button == MouseButtons.Right)
			{
				cmPartEdit.Show(ppPreview, e.Location);
			}
		}

		float Distance2Edge(Vector2 p, EditablePart.Shape.Edge edge)
		{
			Vector2 p1 = edge.Point;
			Vector2 p2;
			p2.X = edge.Point.X + edge.LengthSinCos.X * edge.LengthSinCos.Z;
			p2.Y = edge.Point.Y + edge.LengthSinCos.X * edge.LengthSinCos.Y;

			Vector2 v = p2 - p1;
			Vector2 w = p - p1;

			// See if p is closer to p1 than to the segment
			float c1 = Vector2.Dot(w, v);
			if (c1 <= 0)
				return Vector2.Distance(p, p1);

			// See if p is closer to p2 than to the segment
			float c2 = Vector2.Dot(v, v);
			if (c2 <= c1)
				return Vector2.Distance(p, p2);

			// p is closest to point pB, between p1 and p2
			float b = c1 / c2;
			Vector2 pB = p1 + b * v;
			return Vector2.Distance(p, pB);
		}

		private void miAdd_Click(object sender, EventArgs e)
		{
			Point idx = SelectedIndex;
			AddShape(idx);
		}

		private void miRemove_Click(object sender, EventArgs e)
		{
			RemoveShape(SelectedIndex.X);
		}

		private void AddShape(Point idx)
		{
			part.Shapes.Add(new EditablePart.Shape(part.Shapes[idx.X].Edges[idx.Y]));

			idx.Y = 0;
			idx.X = part.Shapes.Count - 1;

			SelectedIndex = idx;
		}

		private void RemoveShape(int idx)
		{
			part.Shapes.RemoveAt(idx);

			SelectedIndex = new Point(Math.Max(idx - 1, 0), 0);
		}

		private void cmPreview_Opening(object sender, CancelEventArgs e)
		{
			miRemove.Enabled = part.Shapes.Count > 1;

			for (int ii = 1; ii < 15; ++ii)
				for (int jj = 1; jj < 15; ++jj)
					((System.Drawing.Bitmap)miSColor.Image).SetPixel(ii, jj, part.Shapes[SelectedIndex.X].ShapeColor);

			//Yes, I know that this is horrible. But it looks cool :P -Enrico
			for (int ii = 1; ii < 15; ++ii)
				for (int jj = 1; jj < 15; ++jj)
					((System.Drawing.Bitmap)miEColor.Image).SetPixel(ii, jj, part.Shapes[SelectedIndex.X].Edges[SelectedIndex.Y].EdgeColor);
		}

		private void miSColor_Click(object sender, EventArgs e)
		{
			colorDialog.Color = part.Shapes[SelectedIndex.X].ShapeColor;
			if (colorDialog.ShowDialog() == DialogResult.OK)
			{
				part.Shapes[SelectedIndex.X].ShapeColor = colorDialog.Color;

				for (int ii = 0; ii < part.Shapes[SelectedIndex.X].Edges.Count; ++ii)
				{
					part.Shapes[SelectedIndex.X].Edges[ii].EdgeColor = colorDialog.Color;
				}

				ppPreview.Invalidate();
			}
		}

		private void miEColor_Click(object sender, EventArgs e)
		{
			colorDialog.Color = part.Shapes[SelectedIndex.X].Edges[SelectedIndex.Y].EdgeColor;
			if (colorDialog.ShowDialog() == DialogResult.OK)
			{
				part.Shapes[SelectedIndex.X].Edges[SelectedIndex.Y].EdgeColor = colorDialog.Color;

				ppPreview.Invalidate();
			}
		}

		private void miHide_Click(object sender, EventArgs e)
		{
			part.Shapes[SelectedIndex.X].HiddenEdges[SelectedIndex.Y] = true;
			ppPreview.Invalidate();
		}

		private void cbEditMode_DropDownClosed(object sender, EventArgs e)
		{
			ppPreview.Focus();
		}

		private void miEdgeMenu_Click(object sender, EventArgs e)
		{

			number.Number = part.Shapes[SelectedIndex.X].EdgeCount;
			if (number.ShowDialog() == DialogResult.OK)
			{
				part.Shapes[SelectedIndex.X].EdgeCount = number.Number;
			}

			ppPreview.Invalidate();
		}

		private void miShapeUp_Click(object sender, EventArgs e)
		{
			Point idx = SelectedIndex;

			if (idx.X == part.Shapes.Count - 1)
				return;

			EditablePart.Shape tmp = part.Shapes[idx.X];
			part.Shapes[idx.X] = part.Shapes[idx.X + 1];
			part.Shapes[idx.X + 1] = tmp;

			++idx.X;

			SelectedIndex = idx;
		}

		private void miShapeDown_Click(object sender, EventArgs e)
		{
			Point idx = SelectedIndex;

			if (idx.X == 0)
				return;

			EditablePart.Shape tmp = part.Shapes[idx.X];
			part.Shapes[idx.X] = part.Shapes[idx.X - 1];
			part.Shapes[idx.X - 1] = tmp;

			--idx.X;

			SelectedIndex = idx;
		}

		private void miEdgeUp_Click(object sender, EventArgs e)
		{
			Point idx = SelectedIndex;

			if (idx.Y == part.Shapes[idx.X].Edges.Count - 1)
				return;


			EditablePart.Shape.Edge tmp = part.Shapes[idx.X].Edges[idx.Y];
			part.Shapes[idx.X].Edges[idx.Y] = part.Shapes[idx.X].Edges[idx.Y + 1];
			part.Shapes[idx.X].Edges[idx.Y + 1] = tmp;

			++idx.Y;

			SelectedIndex = idx;
		}

		private void miEdgeDown_Click(object sender, EventArgs e)
		{
			Point idx = SelectedIndex;

			if (idx.Y == 0)
				return;


			EditablePart.Shape.Edge tmp = part.Shapes[idx.X].Edges[idx.Y];
			part.Shapes[idx.X].Edges[idx.Y] = part.Shapes[idx.X].Edges[idx.Y - 1];
			part.Shapes[idx.X].Edges[idx.Y - 1] = tmp;

			--idx.Y;

			SelectedIndex = idx;
		}



	}
}